﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using uTrade.Common;
using uTrade.Core;
using uTrade.Data;
using uTrade.Forms;
using uTrade.Strategies;

namespace uTrade.ViewModels
{
    internal class BackTestViewModel : INotifyPropertyChanged
    {
        private readonly string server_addr = "broadcast.eicp.net:55881";
        public string[] SIM_INTERVALS = new string[] { "Min 1", "Min 3", "Min 5", "Min 10", "Min 15", "Min 30", "Hour 1", "Day 1", "Week 1", "Year 1" };

        public ObservableCollection<StrategyConfig> StrategyConfigs { get; set; }

        private readonly DataProcess dataProcess;
        public List<string> strategies;
        public List<string> listInsts;
        public List<string> listInstOrders;
        private string selectedStragety = string.Empty;

        private string selectedInst = string.Empty;
        private string selectedInstOrder = string.Empty;
        private string selectedInterval = string.Empty;
        private string selecteStartdDate = string.Empty;
        private string selecteEnddDate = string.Empty;

        //定义命令属性
        public ICommand SelectionChangedCommand { get; set; }

        public ICommand AddStragCommand { get; set; }

        public BackTestViewModel()
        {
            dataProcess = new DataProcess(server_addr);
            StrategyConfigs = new ObservableCollection<StrategyConfig>();
            strategies = new List<string>();
            listInsts = new List<string>();
            listInstOrders = new List<string>();
            //4.策略列表
            LoadStrategies();
            LoadStrategyCfgs();
            //初始化selectionChangedCommand 事件
            SelectionChangedCommand = new DelegateCommand(SelectionChanged, CanselectionChangedCommand);
            AddStragCommand = new DelegateCommand(AddStrag, CanaddStragCommand);
            //AddStragCommand = new RelayCommand()
        }

        //命令的方法
        public void SelectionChanged(object param)
        {
            DataGrid dataGrid = param as DataGrid;
            TestReportViewModel.LoadResult((Strategy)dataGrid.SelectedItem);
            MessageBox.Show("OK");
            Console.WriteLine("OK");
        }

        public void AddStrag(object param)
        {
            // 1.参数校验
            if (string.IsNullOrEmpty(SelectedStragety)) return;
            if (string.IsNullOrEmpty(SelectedInst)) return;
            if (string.IsNullOrEmpty(SelectedInterval)) return;
            Type type = CommonApi.GetStrategy(SelectedStragety);
            Strategy stra = (Strategy)Activator.CreateInstance((Type)type);
            // 2.配置参数
            if (stra.GetParams().Trim('(', ')').Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Length >= 1)
                using (FormParams fp = new FormParams())
                {
                    //参数配置
                    fp.propertyGrid1.SelectedObject = stra;
                    fp.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
                    if (fp.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
                    //stra.Notify("");
                }
            // 3.添加到列表
            StrategyConfig strategyConfig = new StrategyConfig
            {
                Name = (StrategyConfigs.Count + 1).ToString(),
                StragName = SelectedStragety,
                Interval = SelectedInterval,
                BeginDate = Convert.ToDateTime(SelecteStartdDate),
                Params = stra.GetParams(),
                Instrument = SelectedInst,
                InstrumentOrder = SelectedInstOrder
            };
            if (!string.IsNullOrEmpty(SelecteEnddDate))
            {
                strategyConfig.EndDate = Convert.ToDateTime(SelecteEnddDate);
            }
            StrategyConfigs.Add(strategyConfig);
            BackTestStragCfgMgr.Add(strategyConfig);
            LoadDataBar(ref strategyConfig, stra);
        }

        //加载测试指定行的策略的
        private void LoadDataBar(ref StrategyConfig straCfg, Strategy strategy)
        {
            //DataGridViewRow row = this.DataGridViewStrategies.Rows[rid];

            //var inst = row.Cells["Instrument"].Value.ToString();
            //var instOrder = row.Cells["InstrumentOrder"].Value.ToString();
            //var interval = row.Cells["Interval"].Value.ToString();
            //var stra = _dicStrategies[row.Cells["StraName"].Value.ToString()];
            var begin = straCfg.BeginDate.ToString("yyyyMMdd");
            var end = straCfg.EndDate == null ? DateTime.Today.AddDays(7).ToString("yyyyMMdd") : straCfg.EndDate.Value.AddDays(1).ToString("yyyyMMdd");

            //this.DataGridViewStrategies.Rows[rid].Cells["Loaded"].Value = "加载中...";

            straCfg.Status = Core.TaskStatus.Loading;
            TransDatas data = new TransDatas
            {
                Interval = straCfg.Interval.Split(' ').Length == 1 ? 1 : int.Parse(straCfg.Interval.Split(' ')[1]),
                IntervalType = (IntervalType)Enum.Parse(typeof(IntervalType), straCfg.Interval.Split(' ')[0]),
                Instrument = straCfg.Instrument,
                InstrumentOrder = straCfg.InstrumentOrder,
            };

            //需处理成按合约取品种(期权规则与期货不同)
            if (!dataProcess.InstrumentInfo.TryGetValue(straCfg.Instrument, out Instrument instInfo) || !dataProcess.ProductInfo.TryGetValue(instInfo.ProductID, out Product procInfo))
            {
                uLog.LogError("无合约对应的品种信息");
                return;
            }
            data.InstrumentInfo = new InstrumentInfo
            {
                InstrumentID = straCfg.Instrument,
                ProductID = instInfo.ProductID,
                PriceTick = procInfo.PriceTick,
                VolumeMultiple = procInfo.VolumeTuple,
            };

            List<Bar> bars = null;
            if (data.IntervalType != IntervalType.Sec)// == EnumIntervalType.Min || data.IntervalType == EnumIntervalType.Hour)
            {
                if (data.IntervalType >= IntervalType.Day)//取日线数据
                    bars = dataProcess.QueryDay(straCfg.Instrument, begin, end).Select(n => new Bar
                    {
                        DateTime = DateTime.ParseExact(n._id, "yyyyMMdd", null),
                        //TradingDay = int.Parse(n._id),
                        Open = n.Open,
                        High = n.High,
                        Low = n.Low,
                        Close = n.Close,
                        Volume = n.Volume,
                        OpenInterest = n.OpenInterest
                    }).ToList();
                else
                    bars = dataProcess.QueryMin(straCfg.Instrument, begin, end).Select(n => new Bar
                    {
                        DateTime = DateTime.ParseExact(n._id, "yyyy-MM-dd HH:mm:ss", null),
                        //TradingDay = int.Parse(n.TradingDay),
                        Open = n.Open,
                        High = n.High,
                        Low = n.Low,
                        Close = n.Close,
                        Volume = n.Volume,
                        OpenInterest = n.OpenInterest,
                    }).ToList();

                // 取当日数据
                if (straCfg.EndDate == null)
                {
                    var listReal = dataProcess.QueryReal(straCfg.Instrument);
                    bars = (bars ?? new List<Bar>());
                    if (listReal != null)
                        bars.AddRange(listReal.Select(n => new Bar
                        {
                            DateTime = DateTime.ParseExact(n._id, "yyyy-MM-dd HH:mm:ss", null),
                            //TradingDay = int.Parse(n.TradingDay),
                            Open = n.Open,
                            High = n.High,
                            Low = n.Low,
                            Close = n.Close,
                            Volume = n.Volume,
                            OpenInterest = n.OpenInterest
                        }).ToList());
                }
            }

            //=>初始化策略/回测
            strategy.Init(data);
            strategy.LoadHistory(Tuple.Create(data, bars));

            //未设置结束日期=>可订阅并接收行情 TODO::quote
            //if (straCfg.EndDate == null)// && _q != null)
            //{
            //    strategy.EnableTick = true;
            //    foreach (var v in stra.Datas)
            //    {
            //        LogInfo($"行情订阅:{v.Instrument}");
            //        SubscribeInstrument(v.Instrument);
            //        SubscribeInstrument(v.InstrumentOrder);
            //    }
            //}
            uLog.LogInfo($"{strategy.Name,8},策略加载数据完成.");

            straCfg.Status = Core.TaskStatus.Loaded;
            //this.DataGridViewStrategies.Rows[rid].Cells["TickLoad"].Value = "已加载";

            //if (!_offline)
            //{
            //    var colIdx = this.DataGridViewStrategies.Columns.IndexOf(this.DataGridViewStrategies.Columns["Order"]);
            //    if (!(bool)this.DataGridViewStrategies[colIdx, rid].Value) //未被选中
            //    {
            //        var rect = this.DataGridViewStrategies.GetCellDisplayRectangle(colIdx, rid, false);
            //        this.toolTip1.Show("勾选'委托',对接口下单.", this.DataGridViewStrategies, rect.X + 30, rect.Y + 20, 3000);
            //    }
            //}
        }

        //启用命令
        public bool CanselectionChangedCommand(object param)
        {
            return true;
        }

        public bool CanaddStragCommand(object param)
        {
            return true;
        }

        private void LoadStrategies()
        {
            strategies = CommonApi.GetAllStrategies().Select(s => s.FullName).ToList();
            listInsts = dataProcess.InstrumentInfo.Select(n => n.Key).ToList();
            listInsts.Sort();
            for (int i = 0; i < listInsts.Count; i++)
            {
                if (listInsts[i].EndsWith("000"))
                {
                    listInsts.RemoveAt(i);
                    i--;
                }
            }
            listInstOrders.AddRange(listInsts);
        }

        public string SelectedStragety
        {
            get
            {
                return this.selectedStragety;
            }
            set
            {
                if (!this.selectedStragety.Equals(value))
                {
                    this.selectedStragety = value;
                    RaisePropertyChanged("SelectedStragety");
                }
            }
        }

        public string SelectedInst
        {
            get
            {
                return this.selectedInst;
            }
            set
            {
                if (!this.selectedInst.Equals(value))
                {
                    this.selectedInst = value;
                    RaisePropertyChanged("SelectedInst");
                }
            }
        }

        public string SelectedInstOrder
        {
            get
            {
                return this.selectedInstOrder;
            }
            set
            {
                if (!this.selectedInstOrder.Equals(value))
                {
                    this.selectedInstOrder = value;
                    RaisePropertyChanged("SelectedInstOrder");
                }
            }
        }

        public string SelectedInterval
        {
            get
            {
                return this.selectedInterval;
            }
            set
            {
                if (!this.selectedInterval.Equals(value))
                {
                    this.selectedInterval = value;
                    RaisePropertyChanged("SelectedInterval");
                }
            }
        }

        public string SelecteStartdDate
        {
            get
            {
                return this.selecteStartdDate;
            }
            set
            {
                if (!this.selecteStartdDate.Equals(value))
                {
                    this.selecteStartdDate = value;
                    RaisePropertyChanged("SelecteStartdDate");
                }
            }
        }

        public string SelecteEnddDate
        {
            get
            {
                return this.selecteEnddDate;
            }
            set
            {
                if (!this.selecteEnddDate.Equals(value))
                {
                    this.selecteEnddDate = value;
                    RaisePropertyChanged("SelecteEnddDate");
                }
            }
        }

        public List<string> Strategies
        {
            get
            {
                return this.strategies;
            }
            set
            {
                if (!this.strategies.Equals(value))
                {
                    this.strategies = value;
                    RaisePropertyChanged("Customers");
                }
            }
        }

        public List<string> Intervals
        {
            get
            {
                return SIM_INTERVALS.ToList();
            }
        }

        public List<string> Instrments
        {
            get
            {
                return listInsts;
            }
        }

        public List<string> InstrmentOrders
        {
            get
            {
                return listInstOrders;
            }
        }

        /// <summary>
        /// 加载保存的策略到列表里
        /// </summary>
        private void LoadStrategyCfgs()
        {
            //if (File.Exists("strategies.cfg"))
            //{
            //var list = JsonConvert.DeserializeObject<List<StrategyConfig>>(File.ReadAllText("strategies.cfg"));
            var dataSet = BackTestStragCfgMgr.GetList("");
            var list = ModelConvertHelper<StrategyConfig>.ConvertToModel(dataSet.Tables[0]).ToList();
            foreach (var sc in list)
            {
                Type straType = null;

                if (strategies.Contains(sc.StragName))
                {
                    straType = CommonApi.GetStrategy(sc.StragName);
                }
                //类型是否存在
                if (straType == null)
                    continue;
                Strategy stra = (Strategy)Activator.CreateInstance(straType);
                //参数赋值
                if (!string.IsNullOrEmpty(sc.Params.Trim('(', ')')))
                    foreach (var v in sc.Params.Trim('(', ')').Split(','))
                    {
                        stra.SetParameterValue(v.Split(':')[0], v.Split(':')[1]);
                    }

                AddStra(stra, sc.Interval, sc.BeginDate, sc.EndDate, sc.Name);
            }
            //}
        }

        // 策略添加到表中,返回添加后的行号
        private StrategyConfig AddStra(Strategy stra, string pInterval, DateTime pBegin, DateTime? pEnd, string pName = "Invalid")
        {
            if (pName == "Invalid")
            {
                if (StrategyConfigs.Count == 0)
                {
                    pName = "1";
                }
                else
                {
                    pName = (StrategyConfigs.Select(n => int.Parse(n.Name)).Max() + 1).ToString();
                }
            }

            stra.Name = pName;
            StrategyConfig strategy = new StrategyConfig
            {
                BeginDate = pBegin,
                EndDate = pEnd,
                Interval = pInterval,
                Name = pName,
                Params = stra.GetParams(),
                StragName = stra.GetType().FullName
            };
            StrategyConfigs.Add(strategy);

            return strategy;
        }

        #region INotifyPropertyChanged属性

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion INotifyPropertyChanged属性

        #region 属性更改方法

        private void RaisePropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion 属性更改方法
    }
}